package org.dtrd.modules.record.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.dtrd.common.util.DateUtils;
import org.dtrd.config.system.Constant;
import org.dtrd.config.system.Constant.RecordType;
import org.dtrd.modules.achievement.service.IDtrdEntRdSigninRecordService;
import org.dtrd.modules.record.entity.bean.MedicalDailyInfo;
import org.dtrd.modules.record.entity.bean.MedicalListInfo;
import org.dtrd.modules.record.entity.bean.MedicalRecordInfo;
import org.dtrd.modules.record.entity.bean.CheckinRecord;
import org.dtrd.modules.record.entity.po.DtrdEntRdSigninMedicalRecord;
import org.dtrd.modules.record.mapper.DtrdEntRdMedicalRecordMapper;
import org.dtrd.modules.record.service.IMedicalRecordService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author 萧
 * @date:2021-08-22
 **/
@Service
@DS("multi-datasource1")
@Slf4j
public class MedicalRecordServiceImpl extends ServiceImpl<DtrdEntRdMedicalRecordMapper, DtrdEntRdSigninMedicalRecord> implements IMedicalRecordService {

    @Autowired
    private IDtrdEntRdSigninRecordService signinRecordService;

    @Override
    public DtrdEntRdSigninMedicalRecord transformRecord(CheckinRecord checkinRecord) {
        DtrdEntRdSigninMedicalRecord dt = new DtrdEntRdSigninMedicalRecord().init();
        dt.setMedicalRecordRemark(checkinRecord.getRemark());
        dt.setMedicalRecordDescribe(checkinRecord.getMedicalDesc());
        dt.setPatientId(checkinRecord.getPatientId());
        dt.setMedicalRecordType(checkinRecord.getSubType());
        dt.setRecordTime(parseStringAsDateTime(checkinRecord.getRecordTime()));
        dt.setRecordDate(parseStringAsDate(checkinRecord.getRecordTime()));
        dt.setMedicalRecordPhoto(checkinRecord.getImages());
        dt.setMedicalRecordStatus(checkinRecord.getMedicalRecordStatus());
        return dt;
    }

    @Override
    public CheckinRecord transformPO(DtrdEntRdSigninMedicalRecord po) {
        if (po == null) {
            return null;
        }
        CheckinRecord checkinRecord = new CheckinRecord();
        checkinRecord.setRecordTime(DateUtils.formatTime(po.getRecordTime()));
        checkinRecord.setRecordTimeHm(DateUtils.formatShortTime(po.getRecordTime()));
        checkinRecord.setDataId(po.getDataId());
        checkinRecord.setImages(po.getMedicalRecordPhoto());
        checkinRecord.setPatientId(po.getPatientId());
        checkinRecord.setRecordType(Constant.RecordType.MEDICAL.getType());
        checkinRecord.setRecordTypeName(Constant.RecordType.MEDICAL.getName());
        checkinRecord.setRemark(po.getMedicalRecordRemark());
        checkinRecord.setMedicalDesc(po.getMedicalRecordDescribe());
        return checkinRecord;
    }

    @Override
    public LambdaQueryWrapper<DtrdEntRdSigninMedicalRecord> generateSelectRecordByDateQuery(Integer patientId,String date, Integer subType) {
        LambdaQueryWrapper<DtrdEntRdSigninMedicalRecord> query = new LambdaQueryWrapper<>();
        query.eq(DtrdEntRdSigninMedicalRecord::getIsDel, 0)
                .eq(DtrdEntRdSigninMedicalRecord::getPatientId,patientId)
                .eq(DtrdEntRdSigninMedicalRecord::getRecordDate, date).eq(DtrdEntRdSigninMedicalRecord::getMedicalRecordType, subType);
        return query;
    }

    @Override
    public boolean saveOrUpdateMedicalRecord(MedicalRecordInfo medicalRecordInfo) {
        Integer patientId = medicalRecordInfo.getPatientId();
        DtrdEntRdSigninMedicalRecord po = new DtrdEntRdSigninMedicalRecord();
        po = po.parseFromDto(medicalRecordInfo);
        Date recordDate = po.getRecordDate();
        LambdaUpdateWrapper<DtrdEntRdSigninMedicalRecord> wrapper = Wrappers.lambdaUpdate(DtrdEntRdSigninMedicalRecord.class)
                .eq(DtrdEntRdSigninMedicalRecord::getMedicalRecordType, medicalRecordInfo.getMedicalRecordType())
                .eq(DtrdEntRdSigninMedicalRecord::getRecordDate, recordDate)
                .eq(DtrdEntRdSigninMedicalRecord::getPatientId, patientId);
        boolean result = saveOrUpdate(po, wrapper);
        log.info("MedicalRecordServiceImpl.saveOrUpdateMedicalRecord.[medicalRecordInfo] adfter save patientId=" + patientId + "; result=" + result + "; dataId=" + po.getDataId());
        if (po.getDataId() == null) {
            po = getOne(wrapper);
        }
        // 补充打卡
        signinRecordService.saveSigninRecord(po.getDataId(), medicalRecordInfo.getMedicalRecordType(), mapper ->
                mapper.apply(patientId)
                        .withRecordType(RecordType.MEDICAL.getType())
                        .withRecordValue(medicalRecordInfo.getMedicalRecordStatus()+"")
                        .withRecordTime(DateUtils.formatDate(medicalRecordInfo.getRecordTime(),DateUtils.datetimeFormat.get().toPattern()))
                        .withRecordDesc(medicalRecordInfo.getMedicalRecordDescribe())
                        .withRemark(medicalRecordInfo.getMedicalRecordRemark())
                        .withImages(medicalRecordInfo.getMedicalRecordPhoto())
                        .build()
        );
//        DtrdEntRdSigninMedicalRecord po = getOne(wrapper);
//        signinRecordService.saveSigninRecord(po.getDataId(), patientId,
//                Constant.RecordType.MEDICAL.getType(),
//                medicalRecordInfo.getMedicalRecordType(),
//                DateUtils.formatDate(recordDate, DateUtils.date_sdf.get().toPattern()));
        return result;
    }

    @Override
    public MedicalListInfo getMedicalRecordList(Integer pageNum, Integer pageSize, Integer patientId, String startDate, String endDate) {
        MedicalListInfo medicalListInfo = new MedicalListInfo();
        medicalListInfo.setPatientId(patientId);
        LambdaQueryWrapper<DtrdEntRdSigninMedicalRecord> queryWrapper = Wrappers.lambdaQuery(DtrdEntRdSigninMedicalRecord.class)
                .eq(DtrdEntRdSigninMedicalRecord::getPatientId, patientId)
                .ge(DtrdEntRdSigninMedicalRecord::getRecordDate, startDate)
                .le(DtrdEntRdSigninMedicalRecord::getRecordDate, endDate)
                .orderByDesc(DtrdEntRdSigninMedicalRecord::getRecordDate);
        List<DtrdEntRdSigninMedicalRecord> poList = list(queryWrapper);
        if (CollectionUtil.isEmpty(poList)) {
            medicalListInfo.setCount(0);
            medicalListInfo.setTotalPage(0);
            return medicalListInfo;
        }
        // 转换成 recordDate : 记录列表 的映射
        Map<Date, List<MedicalRecordInfo>> dateToDTO = poList.stream()
                .map(po -> new MedicalRecordInfo().parseFromPo(po))
                .collect(Collectors.groupingBy(MedicalRecordInfo::getRecordDate, Collectors.toList()));
        Set<Date> dates = dateToDTO.keySet();
        List<MedicalDailyInfo> recordList = new ArrayList<>(dateToDTO.size());
        for (Date date : dates) {
            MedicalDailyInfo medicalDailyInfo = new MedicalDailyInfo();
            List<MedicalRecordInfo> medicalRecordInfos = dateToDTO.get(date);
            medicalDailyInfo.setRecordDate(DateUtils.formatDate(date, DateUtils.date_sdf.get().toPattern()));
            for (MedicalRecordInfo info : medicalRecordInfos) {
                Constant.MedicalRecordType medicalRecordType = Constant.MedicalRecordType.valueOf(info.getMedicalRecordType());
                assert medicalRecordType != null;
                switch (medicalRecordType){
                    case MORNING:
                        medicalDailyInfo.setRecordTimeMorning(info.getRecordTime());
                        medicalDailyInfo.setMedicalMorningDesc(info.getMedicalRecordDescribe());
                        medicalDailyInfo.setMedicalMorningPhoto(info.getMedicalRecordPhoto());
                        medicalDailyInfo.setMedicalRecordMorning(info);
                        break;
                    case NOON:
                        medicalDailyInfo.setRecordTimeNoon(info.getRecordTime());
                        medicalDailyInfo.setMedicalNoonDesc(info.getMedicalRecordDescribe());
                        medicalDailyInfo.setMedicalNoonPhoto(info.getMedicalRecordPhoto());
                        medicalDailyInfo.setMedicalRecordNoon(info);
                        break;
                    case EVENING:
                        medicalDailyInfo.setRecordTimeNight(info.getRecordTime());
                        medicalDailyInfo.setMedicalNightDesc(info.getMedicalRecordDescribe());
                        medicalDailyInfo.setMedicalNightPhoto(info.getMedicalRecordPhoto());
                        medicalDailyInfo.setMedicalRecordNight(info);
                        break;
                    case SLEEP:
                        medicalDailyInfo.setRecordTimeBeforeSleep(info.getRecordTime());
                        medicalDailyInfo.setMedicalBeforeSleepDesc(info.getMedicalRecordDescribe());
                        medicalDailyInfo.setMedicalBeforeSleepPhoto(info.getMedicalRecordPhoto());
                        medicalDailyInfo.setMedicalRecordBeforeSleep(info);
                        break;
                }
            }
            recordList.add(medicalDailyInfo);
        }
        // 按日期排序
        recordList.sort(Comparator.comparing(MedicalDailyInfo::getRecordDate, Comparator.reverseOrder()));
        // 处理分页
        int pageStart = (pageNum-1) * pageSize;
        recordList = recordList.stream().skip(pageStart).limit(pageSize).collect(Collectors.toList());
        // 设置返回内容
        int count = dateToDTO.size();
        int totalPage = count / pageSize;
        medicalListInfo.setTotalPage(count % pageSize == 0 ? totalPage : totalPage + 1);
        medicalListInfo.setCount(count);
        medicalListInfo.setRecordList(recordList);
        medicalListInfo.setPage(pageNum);
        return medicalListInfo;
    }

    @Override
    public DtrdEntRdSigninMedicalRecord getMedicalRecordLatestByPatientId(Integer patientId) {
        LambdaQueryWrapper<DtrdEntRdSigninMedicalRecord> wrapper = Wrappers.lambdaQuery(DtrdEntRdSigninMedicalRecord.class)
                .eq(DtrdEntRdSigninMedicalRecord::getPatientId, patientId)
                .orderByDesc(DtrdEntRdSigninMedicalRecord::getCreateTime)
                .last("limit 1");
        return getOne(wrapper);
    }
}
